Server Components 的主要特點是將資料處理和元件渲染都在 Server 端完成,然後再將結果傳送至 Client 端。接下來的內容將著重在如何將在 Server 端生成的 React Component 傳送至 Client 端。這些 Server Components 會被轉換為一種特殊格式,稱為 RSC Payload。
RSC Payload 會是在 Server 端渲染的 React Server Components 樹狀結構,RSC Payload 包含以下內容:
結構會類似這樣:
0:"$L1"
1:["$","h1",null,{"children":"Hello World!"}]
//...
當 RSC Payload 傳送到 Client 端後,會經過轉換變成 React Elements,最後呈現在瀏覽器中。
主要是因為 Server Component 中會包含到 Client Component,而 Client Component 會包含狀態和事件處理函數,這些內容無法被簡單序列化。RSC Payload 能夠更方便地處理這些狀態,並確保在重新渲染的過程中,這些狀態相關的內容可以被正確保留。
RSC Payload 會透過 createFromFetch
轉換成 React Element。以下是簡單的範例說明:
import { use } from "react";
import { createFromFetch } from "react-server-dom-esm/client";
const initialContentPromise = createFromFetch(fetch("/rsc?...")); // RSC Payload
function Root() {
const content = use(initialContentPromise);
return content;
}
createFromFetch
將 RSC Payload 轉換成 React Element,並且透過 use
取得 Promise 的內容,也就是轉換過後回傳的 React Element。
"use client"
做了什麼?"use client"
可以當成 Client 和 Server 的邊界。或者是根據 Dan Abramov 的說法,可以想成是前往 Client 世界的門。
當偵測到 "use client"
時,會將其轉換為使用模組的引用。在 RSC Payload 中,Client Component 會以模組引用的形式存在,會類似下面這樣:
b:I["/some-component.js","SomeComponent"]
前面會是模組的路徑位置,後面則是需要導出的內容。
雖然 Server Components 也可以在 CSR 使用,但大部分框架都是支援 SSR 的。以下是使用 SSR 和 Server Components 的運作流程:
createFromFetch
將 RSC Payload 轉換成 React Element。後續重新渲染:如果因為用戶操作或資料變更需要重新渲染某些 Component,Server 端會生成新的 RSC Payload 傳到 Client 端,Client 端再更新 DOM。
這篇文章沒有討論到 Server Functions、Async Component 和 router 等相關內容,這些內容的整合起來會很複雜,所以都會是使用框架來實作,像是 Next.js 或是 Remix 等。
參考資料:
https://www.plasmic.app/blog/how-react-server-components-work
https://www.youtube.com/watch?v=pOo7x8OiAec
https://www.youtube.com/watch?v=ozI4V_29fj4
https://nextjs.org/docs/app/building-your-application/rendering/server-components#how-are-server-components-rendered
https://www.smashingmagazine.com/2024/05/forensics-react-server-components/